#include "gamescene.h"

#include <QDebug>
#include <QImage>
#include <QMouseEvent>
#include <QPainter>
#include <QPropertyAnimation>
#include <QRandomGenerator>
#include <QTimer>
#include <QPixmap>

#include "card.h"
#include "cards.h"
#include "player.h"
//#include "endscene.h"
#include "ui_gamescene.h"

GameScene::GameScene(QWidget* parent): QMainWindow(parent), myui(new Ui::GameScene) {
    myui->setupUi(this);

    //随机选取背景图
    int num = QRandomGenerator::global()->bounded(2);
    QString path = QString(":/images/background-%1.jpg").arg(num + 1);
    mycardBackImg.load(path);

    //窗口的标题的大小
    this->setWindowTitle("乌龟");
    this->setFixedSize(1000, 650);

    //设置游戏控制
    setcpu();

    //卡牌图片
    setCardMap();

    //初始化玩家在窗口中的上下文环境(牌组，头像的位置)
    setPlayerContext();

    //卡牌场景初始化
    setGameScene();
}

GameScene::~GameScene() { delete myui; }

void GameScene::setcpu() {
    mycpu = new cpu(this);
    mycpu->setPlayer();
    // 得到三个玩家的实例对象
    Player* leftRobot;
    Player* rightRobot;
    Player* user;
    QVector<Player*> tempplayer;
    // 存储的顺序: 左侧机器人, 右侧机器人, 当前玩家
    myplayerList << leftRobot << rightRobot << user;
//    connect(mycpu, &cpu::playerStatusChanged, this, &GameScene::playerStatus);
//    connect(mycpu, &cpu::gameStatusChanged, this, &GameScene::gameStatusPrecess);
//    connect(mycpu, &cpu::noticePlayCards, this, &GameScene::disposePlayCards);

//    connect(leftRobot, &Player::noticeGiveCards, this, &GameScene::disposeCards);
//    connect(rightRobot, &Player::noticeGiveCards, this, &GameScene::disposeCards);
//    connect(user, &Player::noticeGiveCards, this, &GameScene::disposeCards);
}

void GameScene::setCardMap() {
    QString str1[4]={"diamond","club","heart","spade"};
    QString str2[13]={"point_3","point_4","point_5","point_6","point_7","point_8","point_9",
                      "point_10","point_11","point_12","point_13","point_14","point_15"};
    QPixmap backpic = QPixmap(":/images/rear.jpg");
    mycardBackImg = backpic;
    for (int i = 0, color = Card::Diamond; color <= Card::Spade; color++, i++) {
        for (int j = 0, point = Card::Point_3; point <= Card::Point_15; point++, j++) {
            Card card((Card::CardPoint)point, (Card::CardColor)color);  //强转
            QPixmap pixmap = QPixmap(":/images/"+str1[i]+"_"+str2[j]+".png");
            cropImage(pixmap, card);
        }
    }
}

void GameScene::cropImage(QPixmap &pix, Card card) {
    CardPanel* panel = new CardPanel(this);
    mycardSize.setWidth(mycardBackImg.width());
    mycardSize.setHeight(mycardBackImg.height());
    panel->setImage(pix, mycardBackImg);
    panel->setCards(card);
    panel->hide();
    mycardMap.insert(card, panel);
    connect(panel, &CardPanel::cardSelected, this, &GameScene::cardSelected);
}

void GameScene::setPlayerContext() {
    // 1. 放置玩家扑克牌的区域
    const QRect cardsRect[] = {
        // x, y, width, height
        QRect(90, 130, 100, height() - 200),                    // 左侧机器人
        QRect(rect().right() - 190, 130, 100, height() - 200),  // 右侧机器人
        QRect(250, rect().bottom() - 120, width() - 500, 100)   // 当前玩家
    };
    // 2.玩家出牌区域
    const QRect playHandRect[] = {
        QRect(260, 150, 100, 100),                             // 左侧机器人
        QRect(rect().right() - 360, 150, 100, 100),            // 右侧机器人
        QRect(150, rect().bottom() - 290, width() - 300, 105)  // 当前玩家
    };

    // 循环，将上下文信息传递给各个玩家
    int index = myplayerList.indexOf(mycpu->getUser());  //获取的玩家对象的索引值
    for (int i = 0; i < myplayerList.size(); ++i) {
        PlayerContext context;
        context.align = i == index ? Horizontal : Vertical;  //设置布局 玩家水平 机器人竖直
        context.isFront = i == index ? true : false;    //玩家正面显示 机器人反面显示
        context.cardRect = cardsRect[i];  //指定卡牌存放区域
        context.playArea = playHandRect[i];  //出牌区域
        // 提示信息 显示到出牌区域的中心位置
        mycontextMap.insert(myplayerList.at(i), context);  //存入map中 key=玩家 value=上下文环境
        // 玩家名称
        context.myname = new QLabel(PlayerName);
        context.myname->resize(184, 50);
        context.myname->hide();
        context.myname->move(366,250);
    }
}

void GameScene::setGameScene() {
    // 1. 发牌区的扑克牌
    mybaseCard = new CardPanel(this);
    mybaseCard->setImage(mycardBackImg, mycardBackImg);  //不需要显示正面
    // 2. 发牌过程中移动的扑克牌
    mymoveCard = new CardPanel(this);
    mymoveCard->setImage(mycardBackImg, mycardBackImg);  //不需要显示正面
    // 3. 最后的底牌(用于窗口的显示)
    CardPanel* panel = new CardPanel(this);
    panel->setImage(mycardBackImg, mycardBackImg);  //不需要显示正面
    panel->hide();
    // 发牌扑克牌的位置
    mybaseCardPos = QPoint((width() - mycardSize.width()) / 2, height() / 2 - 100);
    mybaseCard->move(mybaseCardPos);
    mymoveCard->move(mybaseCardPos);  //起始位置

    int base = (width() - mycardSize.width() - 2 * 10) / 2;  //乌龟牌的x轴起始坐标
    myTurtleCard->move(base, 20);
}

void GameScene::gameStatusPrecess(cpu::GameStatus status) {
    // 记录游戏状态
    mygameStatus = status;
    // 处理游戏状态
    switch (status) {
    case cpu::DispatchCard:
        startGiveCards();
        break;
    case cpu::PlayingCards:
        // 隐藏发牌区的底牌和移动的牌
        mybaseCard->hide();
        mymoveCard->hide();
        break;
    case cpu::End:
        myTurtleCard->show();
    default:
        break;
    }
}

//发牌
void GameScene::startGiveCards() {
    // 重置每张卡牌的属性
    for (auto it = mycardMap.begin(); it != mycardMap.end(); ++it) {
        it.value()->setSeclected(false);  //设置卡牌选中状态
        it.value()->setFrontSide(true);   //设置卡牌显示面
        it.value()->hide();               //隐藏
    }
    // 隐藏三张底牌
    myTurtleCard->hide();
    // 重新发牌，需要重置玩家的窗口上下文信息
    int index = myplayerList.indexOf(mycpu->getUser());
    for (int i = 0; i < myplayerList.size(); ++i) {
        mycontextMap[myplayerList.at(i)].lastCards.clear();
        mycontextMap[myplayerList.at(i)].isFront = i == index ? true : false;
    }
    // 重置所有玩家的卡牌数据
    mycpu->resetCardData();
}

//单步移动
void GameScene::cardMove(Player* player, int curPos) {
    // 得到每个玩家的扑克牌展示区域
    QRect cardRect = mycontextMap[player].cardRect;
    // 每个玩家的单元步长
    const int unit[] = {(mybaseCardPos.x() - cardRect.right()) / 100,
                        (cardRect.left() - mybaseCardPos.x()) / 100,
                        (cardRect.top() - mybaseCardPos.y()) / 100};
    // 每次窗口移动的时候每个玩家对应的牌的实时坐标位置，curpos记录移动的步骤数
    const QPoint pos[] = {
        QPoint(mybaseCardPos.x() - curPos * unit[0], mybaseCardPos.y()),
        QPoint(mybaseCardPos.x() + curPos * unit[1], mybaseCardPos.y()),
        QPoint(mybaseCardPos.x(), mybaseCardPos.y() + curPos * unit[2]),
    };

    // 移动扑克牌窗口
    int index = myplayerList.indexOf(player);
    mymoveCard->move(pos[index]);

    // 临界状态处理
    if (curPos == 0) {
        mymoveCard->show();  //显示移动牌
    }
    if (curPos == 100) {
        mymoveCard->hide();
    }
}

void GameScene::disposeCards(Player* player, const Cards& cards) {
    Cards& myCard = const_cast<Cards&>(cards);
    CardList list = myCard.toCardList();
    for (int i = 1; i < list.size(); i++) {
        Card card1=list.at(i), card2=list.at(i+1);
        if(card1.point()==card2.point()) {
            list.remove(i, i+1);
        }
    }//需检查
    for (int i = 0; i < list.size(); i++) {
        CardPanel* panel = mycardMap[list.at(i)];
        panel->setOwner(player);
    }

    // 更新扑克牌在窗口中的显示
    updatePlayerCards(player);
}

void GameScene::updatePlayerCards(Player* player) {
    Cards cards = player->getCards();
    CardList list = cards.toCardList();

    mycardsRect = QRect();
    myuserCards.clear();
    // 取出展示扑克牌的区域（宽度）
    int cardSpace = 20;
    QRect cardsRect = mycontextMap[player].cardRect;
    for (int i = 0; i < list.size(); i++) {
        CardPanel* panel = mycardMap[list.at(i)];
        panel->show();
        panel->raise();  //设置当前窗口上层显示
        panel->setFrontSide(mycontextMap[player].isFront);

        // 水平/垂直显示
        if (mycontextMap[player].align == Horizontal) {  //水平显示，用户牌组
            int leftX = cardsRect.left() + (cardsRect.width() - (list.size() - 1) * cardSpace - panel->width()) / 2;
            int topY = cardsRect.top() + (cardsRect.height() - mycardSize.height()) / 2;
            if (panel->isSelected()) {  //牌被选中，弹出效果
                topY -= 10;
            }
            panel->move(leftX + cardSpace * i, topY);
            mycardsRect = QRect(leftX, topY, cardSpace * i + mycardSize.width(),mycardSize.height());
            int curWidth = 0;
            if (list.size() - 1 == i) {
                curWidth = mycardSize.width();
            } else {
                curWidth = cardSpace;
            }
            QRect cardRect(leftX + cardSpace * i, topY, curWidth, mycardSize.height());
            myuserCards.insert(panel, cardRect);
        } else {  //垂直显示，机器人牌组
            int leftX = cardsRect.left() + (cardsRect.width() - mycardSize.width()) / 2;
            int topY = cardsRect.top() + (cardsRect.height() - (list.size() - 1) * cardSpace - panel->height()) / 2;
            panel->move(leftX, topY + i * cardSpace);
        }
    }

    // 显示玩家打出的牌
    // 得到当前玩家的出牌区域以及本轮打出的牌
    QRect playCardRect = mycontextMap[player].playArea;
    Cards lastCards = mycontextMap[player].lastCards;
    if (!lastCards.isEmpty()) {
        int playSpacing = 24;
        CardList lastCardList = lastCards.toCardList();
        CardList::ConstIterator itplayed = lastCardList.constBegin();
        for (int i = 1, cardcount=0; i < list.size(); i++) {
            Card temp1 = list.at(i);
            Card temp2 = list.at(i-1);
            if(temp1.point()==temp2.point()){
                cardcount+=2;
                if(i<list.size()-1) i--;
                list.remove(i);
                list.remove(i-1);
            }
        }

        for (int i = 0; itplayed != lastCardList.constEnd(); itplayed++, i++) {
            CardPanel* panel = mycardMap[*itplayed];
            panel->setFrontSide(true);
            panel->raise();
            // 将打出的牌移动到出牌区域
            if (mycontextMap[player].align == Horizontal) {
                int leftBase = playCardRect.left() + (playCardRect.width() -
                         (lastCardList.size() - 1) * playSpacing - panel->width()) / 2;
                int top = playCardRect.top() + (playCardRect.height() - panel->height()) / 2;
                panel->move(leftBase + i * playSpacing, top);
            } else {
                int left = playCardRect.left() + (playCardRect.width() - panel->width()) / 2;
                int top = playCardRect.top();
                panel->move(left, top + i * playSpacing);
            }
            panel->show();
        }
    }
}

void GameScene::setPlayerName(QString name){
    PlayerName = name;
}

////会被计时器信号触发调用
void GameScene::dispatchCards() {
    // 记录扑克牌的位置（移动的步数，需要移动100步）
    static int curMovePos = 0;
    // 当前玩家
    Player* curPlayer = mycpu->getCurrentPlayer();
    if (curMovePos >= 100) {
        // 给玩家发一张牌
        Card card = mycpu->takeOneCard();
        curPlayer->storeDispatchCard(card);  //存储到用户牌组中
        // 切换玩家
        mycpu->setCurrentPlayer(curPlayer->getNextPlayer());
        curMovePos = 0;
        // 发牌动画
        cardMove(curPlayer, curMovePos);  //步数为0 ，显示牌
        // 判断牌是否发完了
        mycpu->setAllCards();
        return;
    }
    // 移动扑克牌
    cardMove(curPlayer, curMovePos);
    curMovePos += 15;  //每次计时器信号 移动15步
}

void GameScene::playerStatus(Player* player, cpu::PlayerStatus status) {
    switch (status) {
    case cpu::ThinkingForPlayCards:
        // 1. 隐藏上一轮打出的牌
        hidePlayerDropCards(player);
        if (player == mycpu->getUser()) {
            mybutton.setText("出牌");
            mybutton.setGeometry(400, 503, 20, 10);
            mybutton.setVisible(true);
        }
        else{
            mybutton.close();
        }
        break;
    case cpu::Winning:
        mycontextMap[mycpu->getLeftRobot()].isFront = true;
        mycontextMap[mycpu->getRightRobot()].isFront = true;
        updatePlayerCards(mycpu->getLeftRobot());
        updatePlayerCards(mycpu->getRightRobot());
        mycpu->setCurrentPlayer(player);
        break;
    default:
        break;
    }
}

//void GameScene::disposePlayCards(Player* player, Cards& cards) {
//    // 存储玩家打出的牌
//    auto it = mycontextMap.find(player);
//    it->lastCards = cards;
//    // 3. 更新玩家剩余的牌
//    updatePlayerCards(player);
//}

void GameScene::cardSelected(Qt::MouseButton button) {
    // 1. 判断是不是出牌状态
    if (mygameStatus == cpu::DispatchCard) {
        return;
    }
    // 2. 判断发出信号的牌的所有者是不是当前用户玩家
    CardPanel* panel = static_cast<CardPanel*>(sender());
    if (panel->getOwner() != mycpu->getUser()) {
        return;
    }
    // 3. 保存当前被选中的牌的窗口对象
    mycurSelCard = panel;
    // 4. 判断参数的鼠标键是左键还是右键
    if (button == Qt::LeftButton) {
        // 设置扑克牌的选中状态
        panel->setSeclected(!panel->isSelected());
        // 更新扑克牌在窗口中的显示
        updatePlayerCards(panel->getOwner());
        // 保存或删除扑克牌窗口对象
        QSet<CardPanel*>::const_iterator it = myselectCards.find(panel);
        if (it == myselectCards.constEnd()) {
            myselectCards.insert(panel);
        } else {
            myselectCards.erase(it);
        }
    } else if (button == Qt::RightButton) {
        // 调用出牌按钮的槽函数
        userPlayCards();
    }
}

void GameScene::userPlayCards() {
    // 判断游戏状态
    if (mygameStatus != cpu::PlayingCards) {
        return;
    }
    // 判断玩家是不是用户玩家
    if (mycpu->getCurrentPlayer() != mycpu->getUser()) {
        return;
    }
    // 判断要出的牌是否为空
    if (myselectCards.isEmpty()) {
        return;
    }
    Cards temp = (*myselectCards.begin())->getCards();
    // 通过玩家对象出牌
    mycpu->getUser()->playCards(temp);
    // 清空容器
    myselectCards.clear();
}

void GameScene::hidePlayerDropCards(Player* player) {
  auto it = mycontextMap.find(player);
  if (it != mycontextMap.end()) {
    if (it->lastCards.isEmpty()) {
    } else {
      // Cards --> Card
      CardList list = it->lastCards.toCardList();
      for (auto last = list.begin(); last != list.end(); ++last) {
        mycardMap[*last]->hide();
      }
    }
    it->lastCards.clear();
  }
}

void GameScene::paintEvent(QPaintEvent* ev) {
    Q_UNUSED(ev)
    QPainter p(this);
    p.drawPixmap(rect(), mycardBackImg);
}

void GameScene::mouseMoveEvent(QMouseEvent* ev) {
    Q_UNUSED(ev)
    if (ev->buttons() & Qt::LeftButton) {
        QPoint pt = ev->pos();
        if (!mycardsRect.contains(pt)) {
            mycurSelCard = nullptr;
        } else {
            QList<CardPanel*> list = myuserCards.keys();
            for (int i = 0; i < list.size(); i++) {
                CardPanel* panel = list.at(i);
                if (myuserCards[panel].contains(pt) && mycurSelCard != panel) {
                    // 点击这张扑克牌
                    panel->clicked();
                    mycurSelCard = panel;
                }
            }
        }
    }
}
